package main

import (
	"bufio"
	"flag"
	"fmt"
	"os"
	"strings"
)

// isCompleteExpression checks if the input contains a complete expression
func isCompleteExpression(input string) bool {
	trimmed := strings.TrimSpace(input)
	if trimmed == "" {
		return false
	}

	// Check if this is a comment-only line
	// Remove comments and see if anything remains
	trimmedWithoutComments := removeComments(trimmed)
	if strings.TrimSpace(trimmedWithoutComments) == "" {
		// Only comments (and whitespace), treat as complete
		return true
	}

	// Count parentheses balance
	parenBalance := countParens(trimmed)

	// Expression is complete if parentheses are balanced (or it's a simple atom)
	return parenBalance == 0
}

// removeComments removes comment portions from input
func removeComments(input string) string {
	var result strings.Builder
	inString := false
	escaped := false

	for _, char := range input {
		if escaped {
			result.WriteRune(char)
			escaped = false
			continue
		}

		if char == '\\' && inString {
			result.WriteRune(char)
			escaped = true
			continue
		}

		if char == '"' {
			inString = !inString
			result.WriteRune(char)
			continue
		}

		if char == ';' && !inString {
			// Start of comment - stop processing this line
			break
		}

		result.WriteRune(char)
	}

	return result.String()
}

// readMultilineInput reads input until a complete expression is entered
func readMultilineInput(reader *bufio.Reader) (string, error) {
	var lines []string
	prompt := "> "

	for {
		fmt.Print(prompt)
		input, _, err := reader.ReadLine()
		if err != nil {
			return "", err
		}

		line := string(input)
		lines = append(lines, line)

		// Combine all lines so far
		combined := strings.Join(lines, " ")
		trimmed := strings.TrimSpace(combined)

		// Check for exit commands
		if trimmed == "exit" || trimmed == "quit" {
			return trimmed, nil
		}

		// Skip empty input
		if trimmed == "" {
			return "", nil
		}

		// Check if we have a complete expression
		if isCompleteExpression(combined) {
			return combined, nil
		}

		// Continue reading - change prompt to indicate continuation
		prompt = "> "
	}
}

func main() {
	// Parse command line arguments
	cmdFlag := flag.String("c", "", "execute given command(s)")
	flag.Parse()

	// Initialize the global environment
	env := NewGlobalEnvironment()

	// Handle command line execution (-c flag)
	if *cmdFlag != "" {
		result, err := EvalString(*cmdFlag, env)
		if err != nil {
			fmt.Printf("Error: %v\n", err)
			os.Exit(1)
		}
		if result != nil {
			fmt.Printf("%s\n", result.String())
		}
		return
	}

	// Handle file execution
	args := flag.Args()
	if len(args) > 0 {
		// Execute files in order
		for _, filename := range args {
			// Use the same approach as builtinLoad function
			loadExpr := fmt.Sprintf(`(load "%s")`, filename)
			_, err := EvalString(loadExpr, env)
			if err != nil {
				fmt.Printf("Error loading file %s: %v\n", filename, err)
				os.Exit(1)
			}
		}
		return
	}

	// Start REPL if no arguments provided
	fmt.Println("Welcome to AScheme - A Simple Scheme Interpreter")
	fmt.Println("Type 'exit' to quit")
	fmt.Println("Multi-line expressions are supported - continue typing until parentheses are balanced")
	fmt.Println()

	reader := bufio.NewReader(os.Stdin)
	for {
		// Read potentially multi-line input
		input, err := readMultilineInput(reader)
		if err != nil {
			// Handle EOF gracefully
			if err.Error() == "EOF" {
				fmt.Println("\nGoodbye!")
				break
			}
			fmt.Println("Error reading input:", err)
			continue
		}

		line := strings.TrimSpace(input)
		if line == "exit" || line == "quit" {
			fmt.Println("Goodbye!")
			break
		}

		if line == "" {
			continue
		}

		// Skip comment-only lines
		if strings.TrimSpace(removeComments(line)) == "" {
			continue
		}

		// Process the input
		result, err := EvalString(line, env)
		if err != nil {
			fmt.Printf("Error: %v\n", err)
		} else {
			fmt.Printf("%s\n", result.String())
		}
	}
}
